/*
 * Copyright (C) 2010 Moduad Co., Ltd.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.androidpn.server.xmpp.handler;

import java.util.List;

import org.androidpn.server.entity.FriendGroup;
import org.androidpn.server.entity.Role;
import org.androidpn.server.entity.Role.RoleStatus;
import org.androidpn.server.entity.User;
import org.androidpn.server.service.FriendGroupService;
import org.androidpn.server.service.RoleService;
import org.androidpn.server.service.ServiceLocator;
import org.androidpn.server.service.UserNotFoundException;
import org.androidpn.server.service.UserService;
import org.androidpn.server.xmpp.UnauthorizedException;
import org.androidpn.server.xmpp.packet.RolePacket;
import org.androidpn.server.xmpp.packet.RolePacket.Operation;
import org.androidpn.server.xmpp.push.PushRoomToClientThread;
import org.androidpn.server.xmpp.session.ClientSession;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.jivesoftware.smack.util.StringUtils;
import org.xmpp.packet.IQ;
import org.xmpp.packet.PacketError;

/**
 * This class is to handle the TYPE_IQ jabber:iq:roster protocol.
 * 
 * @author Sehwan Noh (devnoh@gmail.com)
 */
public class IQRoleHandler extends IQHandler {

	private static final String NAMESPACE = "jabber:iq:role";

	private RoleService roleService;

	private UserService userService;

	private FriendGroupService friendGroupService;

	/**
	 * Constructor.
	 */
	public IQRoleHandler() {
		roleService = (RoleService) ServiceLocator
				.getService(ServiceLocator.ROLE_SERVICE);
		userService = (UserService) ServiceLocator
				.getService(ServiceLocator.USER_SERVICE);
		friendGroupService = (FriendGroupService) ServiceLocator
				.getService(ServiceLocator.FRIEND_GROUP_SERVICE);
	}

	/**
	 * Handles the received IQ packet.
	 * 
	 * @param packet
	 *            the packet
	 * @return the response to send back
	 * @throws UnauthorizedException
	 *             if the user is not authorized
	 */
	public IQ handleIQ(IQ packet) throws UnauthorizedException {
		IQ reply = null;

		ClientSession session = sessionManager.getSession(packet.getFrom());

		try {
			Element query = packet.getChildElement();
			reply = IQ.createResultIQ(packet);
			String operationStr = query.elementText("operation");
			if (operationStr != null && !operationStr.equals("")) {
				RolePacket.Operation operation = Operation
						.valueOf(operationStr);
				switch (operation) {
				case addRole:
					saveRole(reply, session, query);
					break;
				case checkNickname:
					checkNickname(reply, query);
					break;
				case getMyRoles:
					getMyRoles(reply, session);
					break;
				case loginRole:
					loginRole(reply, session, query);
					break;
				case gameReady:
					gameReady(query);
					break;
				case cancelGameReady:
					cancelGameReady(query);
					break;
				default:
					reply = null;
					break;
				}
			} else {
				reply = null;
			}
		} catch (Exception e) {
			log.error(e.getMessage());
			reply.setError(PacketError.Condition.feature_not_implemented);
		}
		if (reply != null) {
			session.process(reply);
		}
		return null;
	}

	/**
	 * 游戏准备
	 * 
	 * @param query
	 */
	private void cancelGameReady(Element query) {
		Role role = Role.fromXML(StringUtils.unescapeNode(query
				.elementText("role")));
		role = roleService.find(role.getId());
		role.setIsReady(false);
		roleService.update(role);
		new Thread(new PushRoomToClientThread(role.getRoom().getId(),
				sessionManager)).start();
	}

	/**
	 * 游戏准备
	 * 
	 * @param query
	 */
	private void gameReady(Element query) {
		Role role = Role.fromXML(StringUtils.unescapeNode(query
				.elementText("role")));
		role = roleService.find(role.getId());
		role.setIsReady(true);
		roleService.update(role);
		new Thread(new PushRoomToClientThread(role.getRoom().getId(),
				sessionManager)).start();
	}

	/**
	 * 登陆角色
	 * 
	 * @param reply
	 * @param session
	 * @param query
	 * @throws UserNotFoundException
	 * @throws DocumentException
	 */
	private void loginRole(IQ reply, ClientSession session, Element query)
			throws UserNotFoundException, DocumentException {
		String username = session.getUsername();
		Role role = Role.fromXML(StringUtils.unescapeNode(query
				.elementText("role")));
		role = roleService.getRoleByNicknamAndUsername(role.getNickname(),
				username);
		if (role != null) {
			User user = userService.getUserByUsername(username);
			for (Role userRole : user.getRoles()) {
				userRole.setIsOnline(false);
				userRole.setIsReady(false);
				roleService.update(userRole);
			}
			role.setIsOnline(true);
			roleService.update(role);
			RolePacket rolePacket = new RolePacket();
			rolePacket.setRole(role);
			rolePacket.setTo(session.getAddress());
			if (rolePacket.getChildElementXML() != null) {
				Document doc = DocumentHelper.parseText(rolePacket
						.getChildElementXML());
				Element element = doc.getRootElement();
				reply.setChildElement(element.createCopy());
				reply.setType(IQ.Type.result);
			}
		} else {
			reply.setError(PacketError.Condition.item_not_found);
		}
	}

	/**
	 * 获取当前用户所有的角色信息
	 * 
	 * @param reply
	 * @param session
	 * @throws UserNotFoundException
	 * @throws DocumentException
	 */
	private void getMyRoles(IQ reply, ClientSession session)
			throws UserNotFoundException, DocumentException {
		String username = session.getUsername();
		List<Role> roles = roleService.getRolesByUsername(username);
		RolePacket rolePacket = new RolePacket();
		rolePacket.setRoles(roles);
		rolePacket.setTo(session.getAddress());
		if (rolePacket.getChildElementXML() != null) {
			Document doc = DocumentHelper.parseText(rolePacket
					.getChildElementXML());
			Element element = doc.getRootElement();
			reply.setChildElement(element.createCopy());
			reply.setType(IQ.Type.result);
		}
	}

	/**
	 * 保存Role
	 * 
	 * @param reply
	 * @param session
	 * @param query
	 * @throws UserNotFoundException
	 */
	private void saveRole(IQ reply, ClientSession session, Element query)
			throws UserNotFoundException {
		Role role = Role.fromXML(StringUtils.unescapeNode(query
				.elementText("role")));
		boolean isExist = roleService.nicknameExist(role.getNickname());
		if (isExist) {
			reply.setError(PacketError.Condition.conflict);
		} else {
			User user = userService.getUserByUsername(session.getUsername());
			// 初始化role
			role.setId(null);
			role.setUser(user);
			role.setStatus(RoleStatus.enable);
			role.setIsOnline(false);
			role.setGamesCount(new Long(0));
			role.setGamesLost(new Long(0));
			role.setGamesWon(new Long(0));
			roleService.save(role);

			// 初始化角色好友分组信息
			FriendGroup myFriendGroup = new FriendGroup();
			myFriendGroup.setGroupName("我的好友");
			myFriendGroup.setRole(role);
			myFriendGroup.setIsBlacklist(false);
			FriendGroup blackFriendGroup = new FriendGroup();
			blackFriendGroup.setGroupName("黑名单");
			blackFriendGroup.setRole(role);
			blackFriendGroup.setIsBlacklist(true);
			role.getFriendGroups().add(blackFriendGroup);
			role.getFriendGroups().add(myFriendGroup);
			friendGroupService.save(myFriendGroup);
			friendGroupService.save(blackFriendGroup);
		}
	}

	/**
	 * 检查nickname是否可用
	 * 
	 * @param reply
	 * @param query
	 */
	private void checkNickname(IQ reply, Element query) {
		Role role = Role.fromXML(StringUtils.unescapeNode(query
				.elementText("role")));
		if (role.getNickname() != null && !role.getNickname().equals("")
				&& role.getNickname().length() >= 2
				&& role.getNickname().length() <= 8) {
			boolean isExist = roleService.nicknameExist(role.getNickname());
			if (!isExist) {
			} else {
				reply.setError(PacketError.Condition.conflict);
			}
		} else {
			reply.setError(PacketError.Condition.not_acceptable);
		}
	}

	/**
	 * Returns the namespace of the handler.
	 * 
	 * @return the namespace
	 */
	public String getNamespace() {
		return NAMESPACE;
	}

}
